package com.homedo.microservice.open.service.gateway.zuul.task;


import com.homedo.common.util.Detect;
import com.homedo.microservice.open.service.gateway.bean.enums.forzuulfilter.StatusEnum4ZuulFilter;
import com.homedo.microservice.open.service.gateway.bean.po.Config;
import com.homedo.microservice.open.service.gateway.bean.po.ZuulFilter;
import com.homedo.microservice.open.service.gateway.persistence.dao.ConfigDao;
import com.homedo.microservice.open.service.gateway.persistence.dao.ZuulFilterDao;
import com.homedo.microservice.open.service.gateway.zuul.conf.ZuulCommonConf;
import com.netflix.zuul.DefaultFilterFactory;
import com.netflix.zuul.FilterFactory;
import com.netflix.zuul.groovy.GroovyCompiler;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.List;

@Component
public class ZuulFilterCheckTask {
    @Autowired
    private ZuulFilterDao zuulFilterDao;
    @Autowired
    private ConfigDao configDao;
    @Autowired
    private ZuulCommonConf zuulCommonConf;

    private GroovyCompiler groovyCompiler = new GroovyCompiler();
    private FilterFactory filterFactory = new DefaultFilterFactory();

    private static final Logger LOGGER = LoggerFactory.getLogger(ZuulFilterCheckTask.class);

    @Scheduled(cron = "0/6 * * * * ?")
    public void zuulCommonConfUpdateTask() {
        StopWatch stopWatch = null;
        if (zuulCommonConf.getApplicationLogDetail().get()) {
            stopWatch = new StopWatch();
            stopWatch.start();
            LOGGER.info("自检过滤器任务开始:时间[" + new DateTime().toString("yyyy-MM-dd HH:mm:ss.SSS") + "]");
        }


        this.doSchedule();

        if (zuulCommonConf.getApplicationLogDetail().get()) {
            if (stopWatch != null) {
                stopWatch.stop();
                LOGGER.info("自检过滤器任务结束:时间[" + new DateTime().toString("yyyy-MM-dd HH:mm:ss.SSS") + "],耗时[" + stopWatch.getTotalTimeMillis() + "毫秒]");
            }
        }

    }

    private void doSchedule() {
        ZuulFilter record = new ZuulFilter();
        record.setApplicationName(zuulCommonConf.getApplicationName());
        record.setStatus((int) StatusEnum4ZuulFilter.CHECK_ING.getCode());

        List<ZuulFilter> zuulFilters = zuulFilterDao.getListByRecord(record);
        if (!Detect.notEmpty(zuulFilters)) {
            return;
        }

        zuulFilters.forEach(e -> {
            this.updateCheck(e);
        });
    }

    private void updateCheck(ZuulFilter zuulFilter) {
        StatusEnum4ZuulFilter status = StatusEnum4ZuulFilter.EFFECTIVE;
        try {
            Class clazz = groovyCompiler.compile(zuulFilter.getFilterCode(), zuulFilter.getFilterName());
            if (!Modifier.isAbstract(clazz.getModifiers())) {
                com.netflix.zuul.ZuulFilter filter = (com.netflix.zuul.ZuulFilter) filterFactory.newInstance(clazz);
            }
            LOGGER.info("[自检通过:{}--{}]", zuulFilter.getFilterId(), clazz.getName());
        } catch (Exception e) {
            status = StatusEnum4ZuulFilter.CHECK_FAIL;
            LOGGER.warn("[自检失败:{}--{}]", zuulFilter.getFilterId(), e.getMessage(), e);
        }

        ZuulFilter record = new ZuulFilter();
        record.setId(zuulFilter.getId());
        record.setStatus((int) status.getCode());
        record.setUpdateTime(new Date());

        zuulFilterDao.updateByPrimaryKeySelective(record);

        Boolean disableValue = Boolean.TRUE;
        if (status == StatusEnum4ZuulFilter.EFFECTIVE) {
            disableValue = Boolean.FALSE;
        }

        Config config = new Config();
        config.setName(zuulFilter.getDisablePropertyName());
        config.setApplicationName(zuulFilter.getApplicationName());
        config = configDao.getOneByRecord(config);
        if (config != null) {
            Config updateConfig = new Config();
            updateConfig.setId(config.getId());
            updateConfig.setValue(disableValue.toString());
            updateConfig.setUpdateTime(new Date());

            configDao.updateByPrimaryKeySelective(updateConfig);
        }

    }

}
